// WindowLocker.cpp: implementation of the WindowLocker class.
//
//////////////////////////////////////////////////////////////////////

#include "stdafx.h"
#include "WindowLocker.h"

#ifdef _DEBUG
#undef THIS_FILE
static char THIS_FILE[]=__FILE__;
#define new DEBUG_NEW
#endif

//////////////////////////////////////////////////////////////////////
// Construction/Destruction
//////////////////////////////////////////////////////////////////////

WindowLocker::WindowLocker(CWnd * pWnd, bool bIncludeThis):
m_pWnd(pWnd),
m_bIncludeThis(bIncludeThis),
m_phWndDisable(NULL),
m_cModalStack(0)
{

}

WindowLocker::~WindowLocker()
{
  if (m_phWndDisable) delete m_phWndDisable;
}

void WindowLocker::BeginModalState()
{
	ASSERT(m_pWnd != NULL);
	ASSERT(::IsWindow(m_pWnd->m_hWnd));

	// allow stacking, but don't do anything
	if (++m_cModalStack > 1)
		return;

	// determine top-level parent, since that is the true parent of any
	//  modeless windows anyway...
	CWnd* pParent = m_pWnd->GetTopLevelParent();

	// first count all windows that need to be disabled
	UINT nCount = 0;
	HWND hWnd = ::GetWindow(::GetDesktopWindow(), GW_CHILD);
	while (hWnd != NULL)
	{
		if (::IsWindowEnabled(hWnd) &&
			CWnd::FromHandlePermanent(hWnd) != NULL &&
			IsDescendant(pParent->m_hWnd, hWnd) &&
			::SendMessage(hWnd, WM_DISABLEMODAL, 0, 0) == 0)
		{
      if (m_pWnd->GetSafeHwnd() != hWnd || m_bIncludeThis) // Add by wanghui
        ++nCount;
		}
		hWnd = ::GetWindow(hWnd, GW_HWNDNEXT);
	}
	if (nCount == 0)
		return;

	m_phWndDisable = new HWND[nCount+1];

	// disable all windows connected to this frame (and add them to the list)
	UINT nIndex = 0;
	hWnd = ::GetWindow(::GetDesktopWindow(), GW_CHILD);
	while (hWnd != NULL)
	{
		if (::IsWindowEnabled(hWnd) &&
			CWnd::FromHandlePermanent(hWnd) != NULL &&
			IsDescendant(pParent->m_hWnd, hWnd) &&
			::SendMessage(hWnd, WM_DISABLEMODAL, 0, 0) == 0)
		{
      if (m_pWnd->GetSafeHwnd() != hWnd || m_bIncludeThis) // Add by wanghui
      {
			  ::EnableWindow(hWnd, FALSE);
			  ASSERT(nIndex < nCount);
			  m_phWndDisable[nIndex] = hWnd;
			  ++nIndex;
      }
		}
		hWnd = ::GetWindow(hWnd, GW_HWNDNEXT);
	}

	// terminate the list with a NULL
	ASSERT(nIndex < nCount+1);
	m_phWndDisable[nIndex] = NULL;
}

void WindowLocker::EndModalState()
{
	// pop one off the stack (don't undo modalness unless stack is down to zero)
	if (m_cModalStack == 0 || --m_cModalStack > 0 || m_phWndDisable == NULL)
		return;

	// enable all the windows disabled by BeginModalState
	ASSERT(m_phWndDisable != NULL);
	UINT nIndex = 0;
	while (m_phWndDisable[nIndex] != NULL)
	{
		ASSERT(m_phWndDisable[nIndex] != NULL);
		if (::IsWindow(m_phWndDisable[nIndex]))
			::EnableWindow(m_phWndDisable[nIndex], TRUE);
		++nIndex;
	}
	delete[] (void*)m_phWndDisable;
	m_phWndDisable = NULL;
}

bool WindowLocker::IsDescendant(HWND hWndParent, HWND hWndChild)
	// helper for detecting whether child descendent of parent
	//  (works with owned popups as well)
{
	ASSERT(::IsWindow(hWndParent));
	ASSERT(::IsWindow(hWndChild));

	do
	{
		if (hWndParent == hWndChild)
			return TRUE;

		hWndChild = GetParentOwner(hWndChild);
	} while (hWndChild != NULL);

	return FALSE;
}

HWND WindowLocker::GetParentOwner(HWND hWnd)
{
	// check for permanent-owned window first
	CWnd* pWnd = CWnd::FromHandlePermanent(hWnd);
	if (pWnd != NULL)
		return pWnd->GetOwner()->GetSafeHwnd();

	// otherwise, return parent in the Windows sense
	return (::GetWindowLong(hWnd, GWL_STYLE) & WS_CHILD) ?
		::GetParent(hWnd) : ::GetWindow(hWnd, GW_OWNER);
}
